
#include <cstdio>
#include "member_BSerialPort.h"

using namespace BWE;

member_BSerialPort::member_BSerialPort(BSerialPort* serialPort)
{
	boss = serialPort;
	mode = IO_None;
	baudRate = BSerialPort::BaudNone;
	dataBits = BSerialPort::DataNone;
	direction = BSerialPort::DirectNone;
	flowControl = BSerialPort::FlowNone;
	parity = BSerialPort::ParityNone;
	stopBits = BSerialPort::StopNone;
#ifdef linux
	hcom = -1;
#endif
#ifdef _WIN32
	hcom = INVALID_HANDLE_VALUE;
#endif
}
member_BSerialPort::~member_BSerialPort()
{

}

void member_BSerialPort::freshComState()
{
#ifdef linux
	struct termios newtio, oldtio;
	if (tcgetattr(hcom, &oldtio) != 0)
	{
		perror("SetupSerial 1");
		printf("tcgetattr( fd,&oldtio) -> %d\n", tcgetattr(hcom, &oldtio));
		return;
	}
	bzero(&newtio, sizeof(newtio));
	newtio.c_cflag |= CLOCAL | CREAD;
	newtio.c_cflag &= ~CSIZE;
	switch (dataBits)
	{
	case BSerialPort::Data5:
		newtio.c_cflag |= CS5;
		break;
	case BSerialPort::Data6:
		newtio.c_cflag |= CS6;
		break;
	case BSerialPort::Data7:
		newtio.c_cflag |= CS7;
		break;
	case BSerialPort::Data8:
		newtio.c_cflag |= CS8;
		break;
	}
	switch (parity)
	{
	case BSerialPort::ParityOdd:
		newtio.c_cflag |= PARENB;
		newtio.c_cflag |= PARODD;
		newtio.c_iflag |= (INPCK | ISTRIP);
		break;
	case BSerialPort::ParityEven:
		newtio.c_iflag |= (INPCK | ISTRIP);
		newtio.c_cflag |= PARENB;
		newtio.c_cflag &= ~PARODD;
		break;
	case BSerialPort::ParityMark:
		break;
	case BSerialPort::ParitySpace:
		break;
	default:
		newtio.c_cflag &= ~PARENB;
		break;
	}
	switch (baudRate)
	{
	case BSerialPort::Baud1200:
		cfsetispeed(&newtio, B1200);
		cfsetospeed(&newtio, B1200);
		break;
	case BSerialPort::Baud2400:
		cfsetispeed(&newtio, B2400);
		cfsetospeed(&newtio, B2400);
		break;
	case BSerialPort::Baud4800:
		cfsetispeed(&newtio, B4800);
		cfsetospeed(&newtio, B4800);
		break;
	case BSerialPort::Baud9600:
		cfsetispeed(&newtio, B9600);
		cfsetospeed(&newtio, B9600);
		break;
	case BSerialPort::Baud19200:
		cfsetispeed(&newtio, B19200);
		cfsetospeed(&newtio, B19200);
		break;
	case BSerialPort::Baud38400:
		cfsetispeed(&newtio, B38400);
		cfsetospeed(&newtio, B38400);
		break;
	default:
		cfsetispeed(&newtio, B9600);
		cfsetospeed(&newtio, B9600);
		break;
	}
	switch (stopBits)
	{
	case BSerialPort::StopOne:
		newtio.c_cflag &= ~CSTOPB;
		break;
	case BSerialPort::StopOneAndHalf:
		break;
	case BSerialPort::StopTwo:
		newtio.c_cflag |= CSTOPB;
		break;
	default:
		newtio.c_cflag = 0;
		break;
	}

	newtio.c_cc[VTIME] = 0;
	newtio.c_cc[VMIN] = 0;
	tcflush(hcom, TCIFLUSH);
	if ((tcsetattr(hcom, TCSANOW, &newtio)) != 0)
	{
		perror("com set error");
	}
#endif

#ifdef _WIN32
	if (hcom == INVALID_HANDLE_VALUE)
		return;
	DCB dcb;
	GetCommState(hcom, &dcb);
	dcb.BaudRate = baudRate;
	dcb.fBinary = true;
	dcb.ByteSize = dataBits;
	switch (flowControl)
	{
	case BWE::BSerialPort::FlowNone:
		dcb.fDtrControl = DTR_CONTROL_DISABLE;
		dcb.fRtsControl = DTR_CONTROL_DISABLE;
		break;
	case BWE::BSerialPort::FlowHardware:
		dcb.fDtrControl = DTR_CONTROL_ENABLE;
		dcb.fRtsControl = DTR_CONTROL_ENABLE;
		break;
	case BWE::BSerialPort::FlowSoftware:
		dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
		dcb.fRtsControl = DTR_CONTROL_HANDSHAKE;
		break;
	default:
		break;
	}
	switch (parity)
	{
	case BSerialPort::ParityOdd:
		dcb.Parity = ODDPARITY;
		break;
	case BSerialPort::ParityEven:
		dcb.Parity = EVENPARITY;
		break;
	case BSerialPort::ParityMark:
		dcb.Parity = MARKPARITY;
		break;
	case BSerialPort::ParitySpace:
		dcb.Parity = SPACEPARITY;
		break;
	default:
		dcb.Parity = 0;
		break;
	}
	switch (stopBits)
	{
	case BSerialPort::StopOne:
		dcb.StopBits = ONESTOPBIT;
		break;
	case BSerialPort::StopOneAndHalf:
		dcb.StopBits = ONE5STOPBITS;
		break;
	case BSerialPort::StopTwo:
		dcb.StopBits = TWOSTOPBITS;
		break;
	default:
		dcb.StopBits = ONESTOPBIT;
		break;
	}
	SetCommState(hcom, &dcb);
#endif
}

void member_BSerialPort::checkError()
{
	const char* errorStr = 0;
#ifdef _WIN32
	DWORD error = GetLastError();
	switch (error)
	{
	case ERROR_SUCCESS:
		return;

	case ERROR_FILE_NOT_FOUND:
		errorStr = "SerialPort cannot be found.";
		break;

	case ERROR_PATH_NOT_FOUND:
		errorStr = "The system cannot find the path specified.";
		break;

	case ERROR_TOO_MANY_OPEN_FILES:
		errorStr = "The system cannot open the file.";
		break;

	case ERROR_ACCESS_DENIED:
		errorStr = "Access is denied.";
		break;

	case ERROR_INVALID_HANDLE:
		errorStr = "The handle is invalid.";
		break;

	case ERROR_ARENA_TRASHED:
		errorStr = "The storage control blocks were destroyed.";
		break;

	case ERROR_NOT_ENOUGH_MEMORY:
		errorStr = "Not enough memory resources are available to process this command.";
		break;

	case ERROR_INVALID_BLOCK:
		errorStr = "The storage control block address is invalid.";
		break;

	case ERROR_BAD_ENVIRONMENT:
		errorStr = "The environment is incorrect.";
		break;

	case ERROR_BAD_FORMAT:
		errorStr = "An attempt was made to load a program with an incorrect format.";
		break;

	case ERROR_INVALID_ACCESS:
		errorStr = "The access code is invalid.";
		break;

	case ERROR_INVALID_DATA:
		errorStr = "The data is invalid.";
		break;

	case ERROR_OUTOFMEMORY:
		errorStr = "Not enough memory resources are available to complete this operation.";
		break;

	case ERROR_INVALID_DRIVE:
		errorStr = "The system cannot find the drive specified.";
		break;

	case ERROR_CURRENT_DIRECTORY:
		errorStr = "The directory cannot be removed.";
		break;

	case ERROR_NOT_SAME_DEVICE:
		errorStr = "The system cannot move the file to a different disk drive.";
		break;

	case ERROR_NO_MORE_FILES:
		errorStr = "There are no more files.";
		break;

	case ERROR_WRITE_PROTECT:
		errorStr = "The media is write protected.";
		break;

	case ERROR_BAD_UNIT:
		errorStr = "The system cannot find the device specified.";
		break;

	case ERROR_INVALID_PARAMETER:
		errorStr = "SerialPort parameter is invalid.";
		break;

	default:
		errorStr = "Undefined error.";
		break;
	}
#endif
	printf("%s : %s\n", portName.cstr(), errorStr);
}